﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using AMEE.BeinControl;

namespace BeinDemo1.ViewModel
{
    /// <summary>
    /// Main Winwdow View Model.<para>
    /// Intern enthält dieses ViewModel eine Collection von ViewModels, die über das entsprechende
    /// Property im XAML eingebunden werden können, bspw. durch:
    /// <code>
    /// &lt;ItemsControl ItemsSource="{Binding ViewModels}" /&gt;
    /// </code>
    /// </para><para>
    /// Der Konstruktor erzeugt die Daten (Model MyObject), übergibt sie
    /// dem ViewModel.MyObjectVM und fügt sie der internen ViewModels-Collection hinzu.
    /// Im XAML wird per DataTemplate das GridViewModel zur Darstellung auf UserControls.</para>
    /// </summary>
    class MainWindowVM : ViewModelBase
    {

        #region Fields

        /// <summary>
        /// Sammlung einzerlner view-models, die im MainWindow zusammen dargestellt werden (können)
        /// </summary>
        ObservableCollection<ViewModelBase> _viewModels;

        RelayCommand _saveSettingsCommand;
        RelayCommand _runCommand;
        RelayCommand _shutDownCommand;
        /// <summary>indicates, if RunCommand is being executed.</summary>
        bool _isRunning;
        Stepper _walker;

        #endregion

        #region Properties

        /// <summary>
        /// Gibt die ViewModels
        /// </summary>
        public ObservableCollection<ViewModelBase> ViewModels {
            get {
                if (_viewModels == null) {
                    _viewModels = new ObservableCollection<ViewModelBase>();
                }
                return _viewModels;
            }
        }

        /// <summary>
        /// Gibt das ICommand zum Ausführen einer Schrittfolge.
        /// </summary>
        public ICommand SaveSettingsCommand {
            get {
                if (_saveSettingsCommand == null)
                    _saveSettingsCommand = new RelayCommand(param => saveSettingsExecute(), pred => saveSettingsCanExecute());
                return _saveSettingsCommand;
            }
        }
        /// <summary>
        /// Gets the run command.
        /// </summary>
        public ICommand RunCommand {
            get {
                if (_runCommand == null) {
                    _runCommand = new RelayCommand(param => runExecute(param), pred => runCanExecute());
                }
                return _runCommand;
            }
        }

        /// <summary>
        /// Gets the shut down command.
        /// </summary>
        public ICommand ShutDownCommand {
            get {
                if (_shutDownCommand == null) {
                    _shutDownCommand = new RelayCommand(param => shutDownExecute(), pred => shutDownCanExecute());
                }
                return _shutDownCommand;
            }
        }

        bool _isConnected;
        /// <summary>
        /// Gets a value indicating whether TCP connection to all legs is established.
        /// </summary>
        /// <value>
        /// <c>true</c> if is connected to legs; otherwise, <c>false</c>.
        /// </value>
        public bool IsConnectedToLegs {
            get { return _isConnected; }
            private set {
                _isConnected = value;
                OnPropertyChanged("IsConnectedToLegs");
            }
        }

        #endregion

        /// <summary>
        /// Erzeugt neue ViewModel zur Darstellung der Daten im Hauptfenster.
        /// </summary>
        public MainWindowVM() : base() {
            base.InitializationCompleted += MainWindowVM_InitializationCompleted;
        }

        

        /// <summary>
        /// Initializes this instance. (Called by Base-Constructor)
        /// </summary>
        protected override void Initialize() {
            base.Initialize();
            //var beine = initBeine();
            //if (null != beine) {
            //    Stepper walker = new Stepper(beine[0], beine[1], beine[2], beine[3]);
            //    this._walker = walker;


                //StepperVM stepperVM = new StepperVM(walker);
                //this._viewModels.Add(stepperVM);

                //beine[0].Do(BeinTestCommands.Down);
                //walker.PerformStepCyclus();
                //walker.ShutDown();
            //}
            // Stepper...
            //BeinVM? für State?
        }

        /// <summary>
        /// Initializes the beine.
        /// </summary>
        /// <returns>Bein-Array vl,vr,hl,hr. null, wenn fehlgeschlagen.</returns>
        Bein[] initBeine() {
            Bein[] beine = new Bein[4];
            string ip = null;
            int port = -1;
            // Die Beine:
            try {
                // --- Vorne Links ---
                ip = Properties.Settings.Default.VLIP;
                port = Properties.Settings.Default.VLPort;
                Bein vl = new Bein(ip, port);
                beine[0] = vl;
                // --- Vorne Rechts ---
                ip = Properties.Settings.Default.VRIP;
                port = Properties.Settings.Default.VRPort;
                Bein vr = new Bein(ip, port);
                beine[1] = vr;
                // --- Hinten Links ---
                ip = Properties.Settings.Default.HLIP;
                port = Properties.Settings.Default.HLPort;
                Bein hl = new Bein(ip, port);
                beine[2] = hl;
                // --- Hinten Rechts ---
                ip = Properties.Settings.Default.HRIP;
                port = Properties.Settings.Default.HRPort;
                Bein hr = new Bein(ip, port);
                beine[3] = hr;
            }
            catch (BeinControlException bcEx) {
                System.Windows.MessageBox.Show(bcEx.Message);
                Debug.WriteLine(bcEx.StackTrace, "Error");
                foreach (var bein in beine) {
                    if (null != bein) {
                        bein.Dispose();
                    }
                }
                this.IsConnectedToLegs = false;
                return null;
            }
            setBeinParameter(beine);
            this.IsConnectedToLegs = true;
            return beine;
        }

        /// <summary>
        /// Sets the bein parameter (adc-Werte).
        /// </summary>
        /// <param name="beine">Die beine. {vl, vr, hl, hr}</param>
        void setBeinParameter(Bein[] beine) {
            int a, b, c, d = -1;
            // --- Vorne Links ---
            a = Properties.Settings.Default.VL_A_Up_adc;
            b = Properties.Settings.Default.VL_B_Up_adc;
            c = Properties.Settings.Default.VL_C_Up_adc;
            d = Properties.Settings.Default.VL_D_Up_adc;
            beine[0].TEST_SetUpParameters(a, b, c, d);
            a = Properties.Settings.Default.VL_A_Down_adc;
            b = Properties.Settings.Default.VL_B_Down_adc;
            c = Properties.Settings.Default.VL_C_Down_adc;
            d = Properties.Settings.Default.VL_D_Down_adc;
            beine[0].TEST_SetDownParameters(a, b, c, d);
            // --- Vorne Rechts ---
            a = Properties.Settings.Default.VR_A_Up_adc;
            b = Properties.Settings.Default.VR_B_Up_adc;
            c = Properties.Settings.Default.VR_C_Up_adc;
            d = Properties.Settings.Default.VR_D_Up_adc;
            beine[1].TEST_SetUpParameters(a, b, c, d);
            a = Properties.Settings.Default.VR_A_Down_adc;
            b = Properties.Settings.Default.VR_B_Down_adc;
            c = Properties.Settings.Default.VR_C_Down_adc;
            d = Properties.Settings.Default.VR_D_Down_adc;
            beine[1].TEST_SetDownParameters(a, b, c, d);
            // --- Hinten Links ---
            a = Properties.Settings.Default.HL_A_Up_adc;
            b = Properties.Settings.Default.HL_B_Up_adc;
            c = Properties.Settings.Default.HL_C_Up_adc;
            d = Properties.Settings.Default.HL_D_Up_adc;
            beine[2].TEST_SetUpParameters(a, b, c, d);
            a = Properties.Settings.Default.HL_A_Down_adc;
            b = Properties.Settings.Default.HL_B_Down_adc;
            c = Properties.Settings.Default.HL_C_Down_adc;
            d = Properties.Settings.Default.HL_D_Down_adc;
            beine[2].TEST_SetDownParameters(a, b, c, d);
            // --- Hinten Rechts ---
            a = Properties.Settings.Default.HR_A_Up_adc;
            b = Properties.Settings.Default.HR_B_Up_adc;
            c = Properties.Settings.Default.HR_C_Up_adc;
            d = Properties.Settings.Default.HR_D_Up_adc;
            beine[3].TEST_SetUpParameters(a, b, c, d);
            a = Properties.Settings.Default.HR_A_Down_adc;
            b = Properties.Settings.Default.HR_B_Down_adc;
            c = Properties.Settings.Default.HR_C_Down_adc;
            d = Properties.Settings.Default.HR_D_Down_adc;
            beine[3].TEST_SetDownParameters(a, b, c, d);
        }

        void saveSettingsExecute() {
            Properties.Settings.Default.Save();
            //Übernahme der Werte im Model(-View):
            
        }

        bool saveSettingsCanExecute() {
            return true;
        }

        void MainWindowVM_InitializationCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) {
            if (e.Error != null)
                this.IsConnectedToLegs = false;
        }

        /// <summary>
        /// Indicates, if RunCommand can be executed.
        /// </summary>
        /// <returns></returns>
        bool runCanExecute() {
            return !_isRunning;
        }

        /// <summary>
        /// Executes the RunCommand (asynchronously).
        /// </summary>
        /// <param name="param">String "One": ein Schrittzyklus. String "Multiple": 5 Zyklen</param>
        void runExecute(object param) {
            string para = param as String;
            if (para == null) {
                System.Windows.MessageBox.Show("Ecute Run with " + para);

            //    Debug.WriteLine("StepperVM.runExecute - parameter ist kein String", "Warning");
            //    return;
            //}
            //int count = 0;
            //switch (para) {
            //    case "One":
            //        count = 1;
            //        break;
            //    case "Multiple":
            //        count = 5;
            //        break;
            //    default:
            //        break;
            }
            //var task = new Task(i => performSteps(i), count);
            //task.ContinueWith(tsk => _isRunning = false);
            //task.Start();
            else System.Windows.MessageBox.Show("Ecute Run with " + param.ToString());
        }

        /// <summary>
        /// Call of  PerformStepCyclus() <c>count</c> times.
        /// </summary>
        /// <param name="count">an Integer</param>
        private void performSteps(object count) {
            if (count is int) {
                int cnt = (int)count;
                this._isRunning = true;
                for (int i = 0; i < cnt; i++) {
                    //this.Model.PerformStepCyclus();
                    //this._walker.PerformStepCyclus();
                    System.Windows.MessageBox.Show("Run("+cnt+") Befehl erhalten.");
                }
            }
        }


        bool shutDownCanExecute() {
            return true;
        }

        void shutDownExecute() {
            System.Windows.MessageBox.Show("ShutDown Befehl erhalten.");
        }
    }
}
